namespace EyeSoft.Wpf.Facilities.Conventions
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using System.Reflection;
	using System.Windows;

	public class DefaultViewModelToViewConvention : ViewModelToViewConvention
	{
		protected override Type TryMapTo(Type viewModelType)
		{
			var assemblyName = new AssemblyName(viewModelType.Assembly.FullName).Name;

			var viewName = viewModelType.Name.Replace("ViewModel", null);

			var windowType = typeof(Window);
			var windowTypes =
				viewModelType.Assembly.GetTypes().Where(type => type.IsSubclassOf(windowType)).ToArray();

			var windowTypeByViewModel = TryFindWindowByName(windowTypes, viewName);

			if (windowTypeByViewModel != null)
			{
				return windowTypeByViewModel;
			}

			windowTypeByViewModel = TryFindWindowByName(windowTypes, string.Concat(viewName, "Window"));

			if (windowTypeByViewModel != null)
			{
				return windowTypeByViewModel;
			}

			assemblyName =
				assemblyName.Substring(0, assemblyName.LastIndexOf(".ViewModels", StringComparison.Ordinal));


			var viewTypeName =
				"{WpfApplicationAssemblyName}.{ViewName}, {WpfApplicationAssemblyName}"
					.NamedFormat(assemblyName, viewName);

			var viewType = Type.GetType(viewTypeName, true);

			return viewType;
		}

		private static Type TryFindWindowByName(IEnumerable<Type> windowTypes, string viewName)
		{
			var viewInTheSameAssemblyOfTheViewModel = windowTypes.SingleOrDefault(x => x.Name == viewName);

			return viewInTheSameAssemblyOfTheViewModel;
		}
	}
}